// filesystem standard header
#pragma once
#ifndef _FILESYSTEM_
#define _FILESYSTEM_
#ifndef RC_INVOKED
#include <fstream>
#include <list>
#include <memory>	// for shared_ptr
#include <ctime>	// for time_t
#include <new>	// for nothrow
#include <string>

 #pragma pack(push,_CRT_PACKING)
 #pragma warning(push,3)
 #pragma push_macro("new")
 #undef new



_STD_BEGIN
namespace tr2 {
	namespace sys {
template<class _Path>
	struct slash;
template<class _Path>
	struct dot;
template<class _Path>
	struct colon;
template<class _Path>
	struct _Altslash;

		// ENUM file_type
enum file_type {	// types of files
	status_unknown, file_not_found, regular_file, directory_file,
	symlink_file, block_file, character_file, fifo_file,
	socket_file, type_unknown
	};

		// CLASS file_status
class file_status
	{	// stores file status
public:
	explicit file_status(file_type _Ftype = status_unknown)
		: _Myftype(_Ftype)
		{	// default construct
		}

	file_type type() const
		{	// get file type
		return (_Myftype);
		}

	void type(file_type _Ftype)
		{	// set file type
		_Myftype = _Ftype;
		}

private:
	file_type _Myftype;
	};

		// STRUCT space_info
struct space_info
	{	// space information for a file
	_ULonglong capacity;
	_ULonglong free;
	_ULonglong available;
	};

		// TEMPLATE CLASS _Path_iterator
template<class _Path>
	class _Path_iterator
		: public iterator<
			bidirectional_iterator_tag,
			typename _Path::string_type,
			ptrdiff_t,
			typename _Path::string_type *,
			typename _Path::string_type&>
	{	// bidirectional iterator for basic_path
public:
	typedef _Path_iterator<_Path> _Myt;
	typedef _Path path_type;
	typedef typename _Path::string_type string_type;
	typedef const typename _Path::string_type *pointer;
	typedef const typename _Path::string_type& reference;

	_Path_iterator()
		: _Myptr(0), _Myoff(0)
		{	// construct singular iterator
		}

	_Path_iterator(const path_type& _Pval, size_t _Off)
		: _Myptr(&_Pval), _Myoff(_Off)
		{	// construct iterator
		_Getval();
		}

	_Path_iterator(const _Path_iterator& _Right)
		: _Myptr(_Right._Myptr),
			_Myelem(_Right._Myelem),
			_Myoff(_Right._Myoff)
		{	// copy construct
		}

	_Path_iterator& operator=(const _Path_iterator& _Right)
		{	// copy assign
		_Myptr = _Right._Myptr;
		_Myelem = _Right._Myelem;
		_Myoff = _Right._Myoff;
		return (*this);
		}

	_Path_iterator(_Path_iterator&& _Right)
		: _Myptr(_Right._Myptr),
			_Myelem(_STD move(_Right._Myelem)),
			_Myoff(_Right._Myoff)
		{	// move construct
		}

	_Path_iterator& operator=(_Path_iterator&& _Right)
		{	// move assign
		_Myptr = _Right._Myptr;
		_Myelem = _STD move(_Right._Myelem);
		_Myoff = _Right._Myoff;
		return (*this);
		}

	reference operator*() const
		{	// return designated value
		return (_Myelem);
		}

	pointer operator->() const
		{	// return pointer to class object
		return (_STD pointer_traits<pointer>::pointer_to(**this));
		}

	_Myt& operator++()
		{	// preincrement
 #pragma warning(push)
 #pragma warning(disable: 6011)	/* quiet analyze noise */

 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0 || _Myptr->_Mystr.size() <= _Myoff)
			_DEBUG_ERROR(
				"basic_path<T>::iterator is not incrementable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(_Myptr != 0 && _Myoff < _Myptr->_Mystr.size());
 #endif /* _ITERATOR_DEBUG_LEVEL */

		size_t _Pend = _Myptr->_Prefix_end();
		size_t _Size = _Myptr->_Mystr.size();

		if (_Myoff < _Pend)
			_Myoff = _Pend;	// point past "x:"
		else if (_Myoff == _Pend && _Pend < _Size
			&& _Myptr->_Mystr[_Pend] == slash<path_type>::value)
			{	// point past root "/" and following slashes
			for (++_Myoff; _Myoff < _Size; ++_Myoff)
				if (_Myptr->_Mystr[_Myoff]
					!= slash<path_type>::value)
					break;
			}
		else
			{	// point past slashes followed by stuff
			for (; _Myoff < _Size; ++_Myoff)
				if (_Myptr->_Mystr[_Myoff]
					!= slash<path_type>::value)
					break;
			for (; _Myoff < _Size; ++_Myoff)
				if (_Myptr->_Mystr[_Myoff]
					== slash<path_type>::value)
					break;
			}
		_Getval();
		return (*this);

 #pragma warning(pop)
		}

	_Myt operator++(int)
		{	// postincrement
		_Myt _Tmp = *this;
		++*this;
		return (_Tmp);
		}

	_Myt& operator--()
		{	// predecrement
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Myptr == 0 || _Myoff == 0)
			_DEBUG_ERROR(
				"basic_path<T>::iterator is not decrementable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(_Myptr != 0 && _Myoff != 0);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		size_t _Myoff_sav = _Myoff;
		size_t _Off_back = 0;
		_Myoff = 0;
		do
			{	// scan down to previous
			_Off_back = _Myoff;
			++*this;
			} while (_Myoff < _Myoff_sav);
		_Myoff = _Off_back;
		_Getval();
		return (*this);
		}

	_Myt operator--(int)
		{	// postdecrement
		_Myt _Tmp = *this;
		--*this;
		return (_Tmp);
		}

	bool operator==(const _Myt& _Right) const
		{	// test for iterator equality
		return (_Myptr == _Right._Myptr && _Myoff == _Right._Myoff);
		}

	bool operator!=(const _Myt& _Right) const
		{	// test for iterator inequality
		return (!(*this == _Right));
		}

private:
	void _Getval()
		{	// determine _Myelem
		size_t _Pend = _Myptr->_Prefix_end();
		size_t _Size = _Myptr->_Mystr.size();

		_Myelem.clear();
		if (_Size <= _Myoff)
			;	// off end, no field
		else if (_Myoff < _Pend)
			_Myelem = _Myptr->_Mystr.substr(0, _Pend);	// get "x:"
		else if (_Myoff == _Pend && _Pend < _Size
			&& _Myptr->_Mystr[_Pend] == slash<path_type>::value)
			_Myelem = slash<path_type>::value;	// get "/"
		else
			{	// determine next field as slashes followed by stuff
			size_t _Nslash = 0;
			size_t _Nstuff = 0;

			for (; _Myoff + _Nslash < _Size; ++_Nslash)
				if (_Myptr->_Mystr[_Myoff + _Nslash]
					!= slash<path_type>::value)
					break;
			for (; _Myoff + _Nslash + _Nstuff < _Size; ++_Nstuff)
				if (_Myptr->_Mystr[_Myoff + _Nslash + _Nstuff]
					== slash<path_type>::value)
					break;
			if (0 < _Nstuff)
				_Myelem = _Myptr->_Mystr.substr(_Myoff + _Nslash,
					_Nstuff);	// get "stuff"
			else if (0 < _Nslash)
				_Myelem = dot<path_type>::value;	// get "."
			}
		}

	const path_type *_Myptr;	// pointer to basic_path
	string_type _Myelem;	// current element substring
	size_t _Myoff;	// current offset in basic_path
	};

		// TEMPLATE CLASS basic_path AND FRIENDS
template<class _String,
	class _Traits>
	class basic_path
	{	// stores a pathname
public:
	typedef basic_path<_String, _Traits> path_type;
	typedef _String string_type;
	typedef _Traits traits_type;
	typedef typename _String::value_type value_type;
	typedef typename _Traits::external_string_type external_string_type;

	basic_path()
		{	// default construct
		}

	basic_path(const string_type& _Str)
		{	// construct from string
		*this /= _Str;
		}

	basic_path(const value_type *_Ptr)
		{	// construct from NTBS
		*this /= _Ptr;
		}

	template<class _InIt>
		basic_path(_InIt _First, _InIt _Last)
		{	// construct from [_First, _Last)
		append(_First, _Last);
		}

	basic_path(const basic_path& _Right)
		: _Mystr(_Right._Mystr)
		{	// copy construct
		}

	basic_path& operator=(const basic_path& _Right)
		{	// copy assign
		_Mystr = _Right._Mystr;
		return (*this);
		}

	~basic_path() _NOEXCEPT
		{	// destroy the object
		}

	basic_path(basic_path&& _Right)
		: _Mystr(_STD move(_Right._Mystr))
		{	// move construct
		}

	basic_path& operator=(basic_path&& _Right)
		{	// move assign
		_Mystr = _STD move(_Right._Mystr);
		return (*this);
		}

	basic_path& operator=(const string_type& _Str)
		{	// assign from string
		if (&_Mystr == &_Str)
			return (*this);	// self assignment
		else
			{	// strings differ, clear and append
			clear();
			return (*this /= _Str);
			}
		}

	basic_path& operator=(const value_type *_Ptr)
		{	// assign from NTBS
		clear();
		return (*this /= _Ptr);
		}

	template<class _InIt>
		basic_path& assign(_InIt _First, _InIt _Last)
		{	// assign from [_First, _Last)
		clear();
		return (append(_First, _Last));
		}

	basic_path& operator/=(const basic_path& _Pval)
		{	// append copy
		return (append(_Pval._Mystr.c_str(),
			_Pval._Mystr.c_str() + _Pval._Mystr.size()));
		}

	basic_path& operator/=(const string_type& _Str)
		{	// append string
		return (append(_Str.c_str(),
			_Str.c_str() + _Str.size()));
		}

	basic_path& operator/=(const value_type *_Ptr)
		{	// append NTBS
		const value_type *_Ptr2 = _Ptr;
		for (; *_Ptr2 != 0; ++_Ptr2)
			;
		return (append(_Ptr, _Ptr2));
		}

	template<class _InIt>
		basic_path& append(_InIt _First, _InIt _Last)
		{	// append [_First, _Last)
		string_type _Str = _Mystr;	// avoid overlap
		size_t _Oldsize = _Str.size();
		for (; _First != _Last && *_First != value_type(0); ++_First)
			_Str.push_back(*_First);

		if (_Oldsize + 3 <= _Str.size()
			&& _Str[_Oldsize] == slash<path_type>::value
			&& _Str[_Oldsize + 1] == slash<path_type>::value
			&& _Str[_Oldsize + 2] == colon<path_type>::value)
			_Str.erase(_Oldsize, 3);	// drop leading escape sequence

		for (size_t _Idx = _Oldsize; _Idx < _Str.size(); ++_Idx)
			if (_Str[_Idx] == _Altslash<path_type>::value)
				_Str[_Idx] = slash<path_type>::value;	// convert '\' to '/'

		if (0 < _Oldsize && _Oldsize < _Str.size()
			&& _Str[_Oldsize - 1] != colon<path_type>::value
			&& _Str[_Oldsize - 1] != slash<path_type>::value
			&& _Str[_Oldsize] != slash<path_type>::value)
			_Str.insert(_Oldsize, 1, slash<path_type>::value);	// add '/'

		_Mystr = _Str;	// copy back new filename
		return (*this);
		}

	void clear()
		{	// clear the stored string
		_Mystr.clear();
		}

	void swap(basic_path& _Right)
		{	// swap the stored strings
		_Swap_adl(_Mystr, _Right._Mystr);
		}

	basic_path& remove_leaf()
		{	// remove leaf
		if (!empty() && begin() != --end())
			{	// leaf to remove, back up over it
			size_t _Rend = _Root_end();
			size_t _Idx = _Mystr.size();

			for (; _Rend < _Idx; --_Idx)
				if (_Mystr[_Idx - 1] == slash<path_type>::value)
					break;	// back up over stuff at end
			for (; _Rend < _Idx; --_Idx)
				if (_Mystr[_Idx - 1] != slash<path_type>::value)
					break;	// back up over trailing non-root slashes
			_Mystr.erase(_Idx);
			}
		return (*this);
		}

	basic_path& remove_filename()
		{	// remove leaf
		return (remove_leaf());
		}

	basic_path& replace_extension(const string_type& _Newext = string_type())
		{	// replace extension with _Newext
		if (_Newext.empty() || _Newext[0] == dot<path_type>::value)
			*this = branch_path()
				/ basic_path((stem() + _Newext));
		else
			*this = branch_path()
				/ basic_path((stem() + dot<path_type>::value + _Newext));
		return (*this);
		}

	string_type string() const
		{	// get the stored string
		return (_Mystr);
		}

	string_type file_string() const
		{	// get the stored string, native form
		string_type _Ans;
		size_t _Idx = 0;
		size_t _Size = _Mystr.size();

		if (2 <= _Size && _Mystr[0] == slash<path_type>::value)
			while (_Idx < _Size - 1
				&& _Mystr[_Idx + 1] == slash<path_type>::value)
				++_Idx;	// compress leading slashes
		for (; _Idx < _Size; ++_Idx)
			if (_Mystr[_Idx] == slash<path_type>::value)
				_Ans.append(1, _Altslash<path_type>::value);	// convert '/' to '\'
			else
				_Ans.append(1, _Mystr[_Idx]);
		return (_Ans);
		}

	operator string_type() const
		{	// convert to file string
		return (file_string());
		}

	string_type directory_string() const
		{	// get the stored string, directory form
		return (file_string());
		}

	external_string_type external_file_string() const
		{	// get external form of file string
		return (_Traits::to_external(*this, file_string()));
		}

	external_string_type external_directory_string() const
		{	// get external form of directory string
		return (_Traits::to_external(*this, directory_string()));
		}

	string_type root_name() const
		{	// get root name
		return (_Mystr.substr(0, _Prefix_end()));
		}

	string_type root_directory() const
		{	// get root directory
		size_t _Idx = _Prefix_end();
		if (_Idx < _Mystr.size()
			&& _Mystr[_Idx] == slash<path_type>::value)
			return (string_type(1, slash<path_type>::value));
		else
			return (string_type());
		}

	string_type leaf() const
		{	// get leaf
		return (empty() ? string_type() : *--end());
		}

	string_type filename() const
		{	// get leaf
		return (leaf());
		}

	basic_path root_path() const
		{	// get root path
		return (basic_path(_Mystr.c_str(),
			_Mystr.c_str() + _Root_end()));
		}

	basic_path relative_path() const
		{	// get relative path
		size_t _Idx = _Root_end();
		while (_Idx < _Mystr.size()
			&& _Mystr[_Idx] == slash<path_type>::value)
			++_Idx;	// skip extra '/' after root

		return (basic_path(_Mystr.c_str() + _Idx,
			_Mystr.c_str() + _Mystr.size()));
		}

	basic_path branch_path() const
		{	// get branch path
		basic_path _Ans;
		if (!empty())
			{	// append all but last element
			iterator _End = --end();
			for (iterator _Next = begin(); _Next != _End; ++_Next)
				_Ans /= *_Next;
			}
		return (_Ans);
		}

	basic_path parent_path() const
		{	// get branch path
		return (branch_path());
		}

	string_type basename() const
		{	// pick off base name in leaf before dot
		string_type _Str = leaf();
		size_t _Idx = _Str.rfind(dot<path_type>::value);
		return (_Str.substr(0, _Idx));
		}

	string_type stem() const
		{	// pick off base name in leaf before dot
		return (basename());
		}

	string_type extension() const
		{	// pick off .extension in leaf, including dot
		string_type _Str = leaf();
		size_t _Idx = _Str.rfind(dot<path_type>::value);
		return (_Idx == string_type::npos
			? string_type() : _Str.substr(_Idx));
		}

	bool empty() const
		{	// test if stored string is empty
		return (_Mystr.empty());
		}

	bool is_complete() const
		{	// test if root name is complete
		return (has_root_name() && has_root_directory());
		}

	bool has_root_name() const
		{	// test if root name is nonempty
		return (!root_name().empty());
		}

	bool has_root_directory() const
		{	// test if root directory is nonempty
		return (!root_directory().empty());
		}

	bool has_leaf() const
		{	// test if leaf is nonempty
		return (!leaf().empty());
		}

	bool has_filename() const
		{	// test if leaf is nonempty
		return (has_leaf());
		}

	bool has_root_path() const
		{	// test if root path is nonempty
		return (!root_path().empty());
		}

	bool has_relative_path() const
		{	// test if relative path is nonempty
		return (!relative_path().empty());
		}

	bool has_branch_path() const
		{	// test if branch path is nonempty
		return (!branch_path().empty());
		}

	bool has_parent_path() const
		{	// test if branch path is nonempty
		return (has_branch_path());
		}

	typedef _Path_iterator<path_type> iterator;
	typedef iterator const_iterator;

	iterator begin() const
		{	// get beginning of path
		return (iterator(*this, (size_t)0));
		}

	iterator end() const
		{	// get end of path
		return (iterator(*this, _Mystr.size()));
		}

	size_t _Prefix_end() const
		{	// get end of prefix
		size_t _Idx = _Mystr.find(colon<path_type>::value, 0);
		if (_Idx == _Mystr.npos)
			_Idx = 0;
		else
			++_Idx;
		return (_Idx);
		}

	size_t _Root_end() const
		{	// get end of root
		size_t _Idx = _Prefix_end();
		if (_Idx < _Mystr.size()
			&& _Mystr[_Idx] == slash<path_type>::value)
			++_Idx;
		return (_Idx);
		}

	const value_type *_Ptr() const
		{	// get the stored string NTBS
		return (_Mystr.c_str());
		}

	string_type _Mystr;
	};

template<class _String,
	class _Traits> inline
	void swap(basic_path<_String, _Traits>& _Left,
		basic_path<_String, _Traits>& _Right)
	{	// swap two paths
	_Left.swap(_Right);
	}

template<class _String,
	class _Traits> inline
	basic_path<_String, _Traits>
		operator/(const basic_path<_String, _Traits>& _Left,
			const basic_path<_String, _Traits>& _Right)
	{	// concatenate paths
	basic_path<_String, _Traits> _Ans = _Left;
	return (_Ans /= _Right);
	}

template<class _String,
	class _Traits> inline
	bool operator==(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test for basic_path equality
	return (_Left.string() == _Right.string());
	}

template<class _String,
	class _Traits> inline
	bool operator!=(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test for basic_path inequality
	return (!(_Left == _Right));
	}

template<class _String,
	class _Traits> inline
	bool operator<(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test if _Left < _Right
	return (_Left.string() < _Right.string());
	}

template<class _String,
	class _Traits> inline
	bool operator>(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test if _Left > _Right
	return (_Right < _Left);
	}

template<class _String,
	class _Traits> inline
	bool operator<=(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test if _Left <= _Right
	return (!(_Right < _Left));
	}

template<class _String,
	class _Traits> inline
	bool operator>=(const basic_path<_String, _Traits>& _Left,
		const basic_path<_String, _Traits>& _Right)
	{	// test if _Left >= _Right
	return (!(_Left < _Right));
	}

template<class _String,
	class _Traits> inline
	basic_ostream<typename _String::value_type,
		typename _String::traits_type>&
	operator<<(basic_ostream<typename _String::value_type,
		typename _String::traits_type>& _Ostr,
		const basic_path<_String, _Traits>& _Pval)
	{	// insert a basic_path
	return (_Ostr << _Pval.string());
	}

template<class _String,
	class _Traits> inline
	basic_istream<typename _String::value_type,
		typename _String::traits_type>&
	operator>>(basic_istream<typename _String::value_type,
		typename _String::traits_type>& _Istr,
		basic_path<_String, _Traits>& _Pval)
	{	// extract a basic_path
	_String _Str;
	_Istr >> _Str;
	_Pval = _Str;
	return (_Istr);
	}

		// TEMPLATE CLASS basic_filesystem_error AND FRIENDS
template<class _Path>
	class basic_filesystem_error
		: public system_error
	{	// base of all filesystem-error exceptions
public:
	typedef _Path path_type;

	explicit basic_filesystem_error(const string& _Message,
		error_code _Errcode = error_code())
		: system_error(_Errcode, _Message)
		{	// construct from message string and error code
		}

	basic_filesystem_error(const string& _Message,
		const path_type _Pval1,
		error_code _Errcode)
		: system_error(_Errcode, _Message),
			_Mypval1(_Pval1)
		{	// construct from message string and error code
		}

	basic_filesystem_error(const string& _Message,
		const path_type _Pval1,
		const path_type _Pval2,
		error_code _Errcode)
		: system_error(_Errcode, _Message),
			_Mypval1(_Pval1), _Mypval2(_Pval2)
		{	// construct from message string and error code
		}

	virtual ~basic_filesystem_error() _NOEXCEPT
		{	// destroy the object
		}

	basic_filesystem_error(basic_filesystem_error&& _Right)
		: system_error(_Right.code(), _Right.what()),
			_Mypval1(_STD move(_Right._Mypval1)),
			_Mypval2(_STD move(_Right._Mypval2))
		{	// move construct
		}

	basic_filesystem_error& operator=(basic_filesystem_error&& _Right)
		{	// move assign
		*((system_error *)this) = *(system_error *)&_Right;
		_Mypval1 = _STD move(_Right._Mypval1);
		_Mypval2 = _STD move(_Right._Mypval2);
		return (*this);
		}

	const path_type& path1() const _THROW0()
		{	// return stored first path
		return (_Mypval1);
		}

	const path_type& path2() const _THROW0()
		{	// return stored second path
		return (_Mypval2);
		}

 #if _HAS_EXCEPTIONS

 #else /* _HAS_EXCEPTIONS */
protected:
	virtual void _Doraise() const
		{	// perform class-specific exception handling
		_RAISE(*this);
		}
 #endif /* _HAS_EXCEPTIONS */

private:
	path_type _Mypval1;
	path_type _Mypval2;
	};

		// CLASSES path_traits AND wpath_traits
struct path_traits;
struct wpath_traits;

typedef basic_path<string, path_traits> path;
typedef basic_path<wstring, wpath_traits> wpath;

typedef basic_filesystem_error<path> filesystem_error;
typedef basic_filesystem_error<wpath> wfilesystem_error;

struct path_traits
	{	// traits for char pathnames
	typedef string external_string_type;
	typedef string internal_string_type;

	path_traits()
		: _Is_locked(false)
		{	// default construct
		}

	static external_string_type to_external(const path&,
		const internal_string_type& _Istr)
		{	// convert to external format
		return (_Istr);
		}

	static internal_string_type to_internal(const path&,
		const external_string_type& _Xstr)
		{	// convert to internal format
		return (_Xstr);
		}

	void imbue(locale _Loc);	// deferred

	bool imbue(locale _Loc, nothrow_t)
		{	// imbue unlocked with new locale, return lock status
		if (!_Is_locked)
			_Myloc = _Loc;

		bool _Retval = _Is_locked;
		_Is_locked = true;
		return (_Retval);
		}

private:
	bool _Is_locked;
	locale _Myloc;
	};

struct wpath_traits
	{	// traits for wchar_t pathnames
	typedef wstring external_string_type;
	typedef wstring internal_string_type;

	wpath_traits()
		: _Is_locked(false)
		{	// default construct
		}

	static external_string_type to_external(const wpath&,
		const internal_string_type& _Istr)
		{	// convert to external format
		return (_Istr);
		}

	static internal_string_type to_internal(const wpath&,
		const external_string_type& _Xstr)
		{	// convert to internal format
		return (_Xstr);
		}

	void imbue(locale _Loc);	// deferred

	bool imbue(locale _Loc, nothrow_t)
		{	// imbue unlocked with new locale, return lock status
		if (!_Is_locked)
			_Myloc = _Loc;

		bool _Retval = _Is_locked;
		_Is_locked = true;
		return (_Retval);
		}

private:
	bool _Is_locked;
	locale _Myloc;
	};

template<class _Path>
	struct is_basic_path
		: false_type
	{	// tests whether _Path is a basic_path type
	};

template<>
	struct is_basic_path<path>
		: true_type
	{	// tests whether path is a basic path type
	};

template<>
	struct is_basic_path<wpath>
		: true_type
	{	// tests whether wpath is a basic path type
	};

		// STRUCT slash AND FRIENDS
template<>
	struct slash<path>
	{	// wraps a slash character
static const char value = '/';
	};
template<>
	struct slash<wpath>
	{	// wraps a slash character
static const wchar_t value = L'/';
	};

template<>
	struct dot<path>
	{	// wraps a dot character
static const char value = '.';
	};
template<>
	struct dot<wpath>
	{	// wraps a dot character
static const wchar_t value = L'.';
	};

template<>
	struct colon<path>
	{	// wraps a colon character
static const char value = ':';
	};
template<>
	struct colon<wpath>
	{	// wraps a colon character
static const wchar_t value = L':';
	};

template<>
	struct _Altslash<path>
	{	// wraps a backslash character
static const char value = '\\';
	};
template<>
	struct _Altslash<wpath>
	{	// wraps a backslash character
static const wchar_t value = L'\\';
	};

		// DEFERRED path_traits DEFINITIONS
inline void path_traits::imbue(locale _Loc)
	{	// imbue with new locale
	if (_Is_locked)
		_THROW_NCEE(filesystem_error,
			"path_traits::imbue locked");
	_Is_locked = true;
	_Myloc = _Loc;
	}

inline void wpath_traits::imbue(locale _Loc)
	{	// imbue with new locale
	if (_Is_locked)
		_THROW_NCEE(filesystem_error,
			"wpath_traits::imbue locked");
	_Is_locked = true;
	_Myloc = _Loc;
	}

		// SYSTEM SUPPORT FUNCTIONS

 #ifndef _FS_DLL
  #define _FS_DLL	_CRTIMP2_PURE
 #endif /* _FS_DLL */

 #define _MAX_FILESYS_NAME	260	/* longest Windows or Posix filename + 1 */

	// narrow filenames
_FS_DLL void *__CLRCALL_PURE_OR_CDECL _Open_dir(char (&)[_MAX_FILESYS_NAME],
	const char *, int&, file_type&);
_FS_DLL char *__CLRCALL_PURE_OR_CDECL _Read_dir(char (&)[_MAX_FILESYS_NAME],
	void *, file_type&);
_FS_DLL void __CLRCALL_PURE_OR_CDECL _Close_dir(void *);
_FS_DLL char *__CLRCALL_PURE_OR_CDECL _Current_get(char (&)[_MAX_FILESYS_NAME]);
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Current_set(const char *);

_FS_DLL int __CLRCALL_PURE_OR_CDECL _Make_dir(const char *);
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Remove_dir(const char *);

_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Stat(const char *, int&);
_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Lstat(const char *, int&);
_FS_DLL _ULonglong __CLRCALL_PURE_OR_CDECL _File_size(const char *);
_FS_DLL time_t __CLRCALL_PURE_OR_CDECL _Last_write_time(const char *);
_FS_DLL void __CLRCALL_PURE_OR_CDECL _Last_write_time(const char *, time_t);
_FS_DLL space_info __CLRCALL_PURE_OR_CDECL _Statvfs(const char *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Equivalent(const char *, const char *);

_FS_DLL int __CLRCALL_PURE_OR_CDECL _Link(const char *, const char *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Symlink(const char *, const char *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Rename(const char *, const char *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Unlink(const char *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Copy_file(const char *, const char *, bool);

	// wide filenames
_FS_DLL void *__CLRCALL_PURE_OR_CDECL _Open_dir(wchar_t (&)[_MAX_FILESYS_NAME],
	const wchar_t *, int&, file_type&);
_FS_DLL wchar_t *__CLRCALL_PURE_OR_CDECL _Read_dir(wchar_t (&)[_MAX_FILESYS_NAME],
	void *, file_type&);
//_FS_DLL void __CLRCALL_PURE_OR_CDECL _Close_dir(void *);
_FS_DLL wchar_t *__CLRCALL_PURE_OR_CDECL _Current_get(wchar_t (&)[_MAX_FILESYS_NAME]);
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Current_set(const wchar_t *);

_FS_DLL int __CLRCALL_PURE_OR_CDECL _Make_dir(const wchar_t *);
_FS_DLL bool __CLRCALL_PURE_OR_CDECL _Remove_dir(const wchar_t *);

_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Stat(const wchar_t *, int&);
_FS_DLL file_type __CLRCALL_PURE_OR_CDECL _Lstat(const wchar_t *, int&);
_FS_DLL _ULonglong __CLRCALL_PURE_OR_CDECL _File_size(const wchar_t *);
_FS_DLL time_t __CLRCALL_PURE_OR_CDECL _Last_write_time(const wchar_t *);
_FS_DLL void __CLRCALL_PURE_OR_CDECL _Last_write_time(const wchar_t *, time_t);
_FS_DLL space_info __CLRCALL_PURE_OR_CDECL _Statvfs(const wchar_t *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Equivalent(const wchar_t *, const wchar_t *);

_FS_DLL int __CLRCALL_PURE_OR_CDECL _Link(const wchar_t *, const wchar_t *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Symlink(const wchar_t *, const wchar_t *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Rename(const wchar_t *, const wchar_t *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Unlink(const wchar_t *);
_FS_DLL int __CLRCALL_PURE_OR_CDECL _Copy_file(const wchar_t *, const wchar_t *, bool);

		// TEMPLATE CLASS basic_directory_entry AND FRIENDS
template<class _Path>
	class basic_directory_entry
	{	// represents a directory entry
public:
	typedef basic_directory_entry<_Path> _Myt;
	typedef _Path path_type;
	typedef typename _Path::string_type string_type;

	basic_directory_entry()
		: _Myftype(status_unknown),
			_Mysymftype(status_unknown)
		{	// default construct
		}

	explicit basic_directory_entry(const path_type& _Pval,
		file_status _Statarg = file_status(),
		file_status _Symstatarg = file_status())
		: _Mypval(_Pval),
			_Myftype(_Statarg.type()),
			_Mysymftype(_Symstatarg.type())
		{	// construct from path and status
		}

	basic_directory_entry(const basic_directory_entry& _Right)
		: _Mypval(_Right._Mypval),
			_Myftype(_Right._Myftype),
			_Mysymftype(_Right._Mysymftype)
		{	// copy construct
		}

	basic_directory_entry& operator=(const basic_directory_entry& _Right)
		{	// copy assign
		_Mypval = _Right._Mypval;
		_Myftype = _Right._Myftype;
		_Mysymftype = _Right._Mysymftype;
		return (*this);
		}

	basic_directory_entry(basic_directory_entry&& _Right)
		: _Mypval(_STD move(_Right._Mypval)),
			_Myftype(_Right._Myftype),
			_Mysymftype(_Right._Mysymftype)
		{	// move construct
		}

	basic_directory_entry& operator=(basic_directory_entry&& _Right)
		{	// move assign
		_Mypval = _STD move(_Right._Mypval);
		_Myftype = _Right._Myftype;
		_Mysymftype = _Right._Mysymftype;
		return (*this);
		}

	void assign(const path_type& _Pval,
		file_status _Statarg = file_status(),
		file_status _Symstatarg = file_status())
		{	// assign path and status
		_Mypval = _Pval;
		_Myftype = _Statarg.type();
		_Mysymftype = _Symstatarg.type();
		}

	void replace_leaf(const string_type& _Str,
		file_status _Statarg = file_status(),
		file_status _Symstatarg = file_status())
		{	// replace leaf and assign status
		_Mypval = _Mypval.branch_path() / _Str;
		_Myftype = _Statarg.type();
		_Mysymftype = _Symstatarg.type();
		}

	const path_type& path() const
		{	// get path
		return (_Mypval);
		}

	operator const path_type&() const
		{	// get path
		return (_Mypval);
		}

	file_status status() const
		{	// get file status
		int _Errno = 0;
		if (_Myftype != status_unknown)
			;
		else if (_Mysymftype != status_unknown
			&& _Mysymftype != symlink_file)
			_Myftype = _Mysymftype;
		else
			_Myftype = _Stat(_Mypval._Ptr(), _Errno);
		return (file_status(_Myftype));
		}

	file_status status(error_code& _Code) const
		{	// get file status
		int _Errno = 0;
		if (_Myftype != status_unknown)
			;
		else if (_Mysymftype != status_unknown
			&& _Mysymftype != symlink_file)
			_Myftype = _Mysymftype;
		else
			_Myftype = _Stat(_Mypval._Ptr(), _Errno);
		_Code = error_code(_Errno, _STD system_category());
		return (file_status(_Myftype));
		}

	file_status symlink_status() const
		{	// get file status
		int _Errno = 0;
		if (_Mysymftype == status_unknown)
			_Mysymftype = _Lstat(_Mypval._Ptr(), _Errno);
		return (file_status(_Mysymftype));
		}

	file_status symlink_status(error_code& _Code) const
		{	// get file symlink status
		int _Errno = 0;
		if (_Mysymftype == status_unknown)
			_Mysymftype = _Lstat(_Mypval._Ptr(), _Errno);
		_Code = error_code(_Errno, _STD system_category());
		return (file_status(_Mysymftype));
		}

	bool operator==(const _Myt& _Right) const
		{	// test if *this == _Right
		return (_Mypval == _Right._Mypval);
		}

	bool operator!=(const _Myt& _Right) const
		{	// test if *this == _Right
		return (!(*this == _Right));
		}

	bool operator<(const _Myt& _Right) const
		{	// test if *this < _Right
		return (_Mypval < _Right._Mypval);
		}

	bool operator>(const _Myt& _Right) const
		{	// test if *this > _Right
		return (_Right < *this);
		}
	bool operator<=(const _Myt& _Right) const
		{	// test if *this <= _Right
		return (!(_Right < *this));
		}

	bool operator>=(const _Myt& _Right) const
		{	// test if *this <= _Right
		return (!(*this < _Right));
		}

private:
	path_type _Mypval;
	mutable file_type _Myftype;
	mutable file_type _Mysymftype;
	};

typedef basic_directory_entry<path> directory_entry;
typedef basic_directory_entry<wpath> wdirectory_entry;

template<class _Path,
	class _Prefix_directory = true_type>
	class basic_directory_iterator
		: public iterator<input_iterator_tag, basic_directory_entry<_Path> >
	{	// walks a directory
public:
	typedef basic_directory_iterator<_Path, _Prefix_directory> _Myt;
	typedef basic_directory_entry<_Path> value_type;
	typedef typename _Path::string_type string_type;
	typedef _Path path_type;
	typedef const value_type *pointer;

	basic_directory_iterator()
		: _Mypdir(new void *(0), &_Delptr)
		{	// default construct
		}

	basic_directory_iterator(const _Myt& _Right)
		: _Mypdir(_Right._Mypdir),
			_Mydirpath(_Right._Mydirpath),
			_Myentry(_Right._Myentry)
		{	// copy construct
		}

	basic_directory_iterator(const _Path& _Pval)
		: _Mypdir(new void *(0), &_Delptr),
			_Mydirpath(_Pval)
		{	// construct from _Pval
		typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
		int _Errno = 0;
		file_type _Ftype;

		*_Mypdir = _Open_dir(_Dest, _Pval._Ptr(), _Errno, _Ftype);
		if (*_Mypdir != 0)
			_Form_name(_Dest, _Ftype, _Prefix_directory());
		}

	basic_directory_iterator(const _Path& _Pval, error_code& _Code)
		: _Mypdir(new void *(0), &_Delptr),
			_Mydirpath(_Pval)
		{	// construct from _Pval, errors to _Code
		typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
		int _Errno = 0;
		file_type _Ftype;

		*_Mypdir = _Open_dir(_Dest, _Pval._Ptr(), _Errno, _Ftype);
		if (*_Mypdir != 0)
			_Form_name(_Dest, _Ftype, _Prefix_directory());
		_Code = error_code(_Errno, _STD system_category());
		}

	~basic_directory_iterator() _NOEXCEPT
		{	// destroy the object
		}

	basic_directory_iterator(_Myt&& _Right)
		: _Mypdir(_STD move(_Right._Mypdir)),
			_Mydirpath(_STD move(_Right._Mydirpath)),
			_Myentry(_STD move(_Right._Myentry))
		{	// move construct
		}

	_Myt& operator=(_Myt&& _Right)
		{	// move assign
		if (this != &_Right)
			{	// different, move
			_Mypdir = _STD move(_Right._Mypdir);
			_Mydirpath = _STD move(_Right._Mydirpath);
			_Myentry = _STD move(_Right._Myentry);
			}
		return (*this);
		}

	_Myt& operator=(const _Myt& _Right)
		{	// copy assign
		if (this != &_Right)
			{	// different, copy
			_Mypdir = _Right._Mypdir;
			_Mydirpath = _Right._Mydirpath;
			_Myentry = _Right._Myentry;
			}
		return (*this);
		}

	const value_type& operator*() const
		{	// return designated value
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (*_Mypdir == 0)
			_DEBUG_ERROR(
				"basic_directory_iterator is not dereferencable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(*_Mypdir != 0);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		return (_Myentry);
		}

	pointer operator->() const
		{	// return pointer to class object
		return (_STD pointer_traits<pointer>::pointer_to(**this));
		}

	_Myt& operator++()
		{	// preincrement
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (*_Mypdir == 0)
			_DEBUG_ERROR(
				"basic_directory_iterator is not incrementable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(*_Mypdir != 0);
 #endif /* _ITERATOR_DEBUG_LEVEL */

		_Get();
		return (*this);
		}

	_Myt operator++(int)
		{	// postincrement
		_Myt _Tmp = *this;
		++*this;
		return (_Tmp);
		}

	bool _Equal(const _Myt& _Right) const
		{	// test for equality
		return (_Mypdir.get() != 0 && _Right._Mypdir.get() != 0
			? *_Mypdir == *_Right._Mypdir
			: _Mypdir.get() == 0 && _Right._Mypdir.get() == 0);
		}

private:
	static void _Delptr(void **_Ptr)
		{	// close directory and delete pointer
		if (_Ptr != 0 && *_Ptr != 0)
			_Close_dir(*_Ptr);
		delete _Ptr;
		}

	void _Get()
		{	// peek at next input element
		if (*_Mypdir != 0)
			{	// read a directory entry
			typename string_type::value_type _Dest[_MAX_FILESYS_NAME];
			file_type _Ftype;
			if (_Read_dir(_Dest, *_Mypdir, _Ftype)[0] == 0)
				{	// end of directory, close it
				_Close_dir(*_Mypdir);
				*_Mypdir = 0;	// end of directory
				}
			else
				_Form_name(_Dest, _Ftype, _Prefix_directory());
			}
		}

	void _Form_name(typename string_type::value_type *_Filename,
			file_type _Ftype, true_type)
		{	// set entry to _Mydirpath/_Filename
		_Myentry.assign(_Mydirpath / _Path(_Filename),
			file_status(_Ftype));
		}

	void _Form_name(typename string_type::value_type *_Filename,
			file_type _Ftype, false_type)
		{	// set entry to _Filename
		_Myentry.assign(_Path(_Filename), file_status(_Ftype));
		}

	shared_ptr<void *> _Mypdir;
	_Path _Mydirpath;
	value_type _Myentry;
	};

template<class _Path,
	class _Prefix_directory> inline
	bool operator==(
		const basic_directory_iterator<_Path, _Prefix_directory>& _Left,
		const basic_directory_iterator<_Path, _Prefix_directory>& _Right)
	{	// test for basic_directory_iterator equality
	return (_Left._Equal(_Right));
	}

template<class _Path,
	class _Prefix_directory> inline
	bool operator!=(
		const basic_directory_iterator<_Path, _Prefix_directory>& _Left,
		const basic_directory_iterator<_Path, _Prefix_directory>& _Right)
	{	// test for basic_directory_iterator inequality
	return (!(_Left == _Right));
	}

typedef basic_directory_iterator<path> directory_iterator;
typedef basic_directory_iterator<wpath> wdirectory_iterator;

		// TEMPLATE CLASS basic_recursive_directory_iterator
template<class _Path>
	class basic_recursive_directory_iterator
		: public iterator<input_iterator_tag, basic_directory_entry<_Path> >
	{	// walks a directory
public:
	typedef basic_recursive_directory_iterator<_Path> _Myt;
	typedef basic_directory_iterator<_Path, false_type> _Myiter;
	typedef pair<_Myiter, _Path> _Mypair;

	typedef basic_directory_entry<_Path> value_type;
	typedef typename _Path::string_type string_type;
	typedef typename string_type::value_type char_type;
	typedef _Path path_type;
	typedef const value_type *pointer;

	basic_recursive_directory_iterator()
		: _Mylist(1, _Mypair()),
			_Myentry(),
			_No_push(false)
		{	// default construct
		}

	basic_recursive_directory_iterator(const _Myt& _Right)
		: _Mylist(_Right._Mylist),
			_Myentry(_Right._Myentry),
			_No_push(_Right._No_push)
		{	// copy construct
		}

	basic_recursive_directory_iterator(const _Path& _Pval)
		: _Mylist(1, _Mypair(_Myiter(_Pval), _Pval)),
			_Myentry(),
			_No_push(false)
		{	// construct from _Pval
		_Get();
		}

	~basic_recursive_directory_iterator() _NOEXCEPT
		{	// destroy the object
		}

	basic_recursive_directory_iterator(_Myt&& _Right)
		: _Mylist(_STD move(_Right._Mylist)),
			_Myentry(_STD move(_Right._Myentry)),
			_No_push(_Right._No_push)
		{	// move construct
		}

	_Myt& operator=(_Myt&& _Right)
		{	// move assign
		if (this != &_Right)
			{	// move fields
			_Mylist = _STD move(_Right._Mylist);
			_Myentry = _STD move(_Right._Myentry);
			_No_push = _Right._No_push;
			}
		return (*this);
		}

	_Myt& operator=(const _Myt& _Right)
		{	// copy assign
		if (this != &_Right)
			{	// copy fields
			_Mylist = _Right._Mylist;
			_Myentry = _Right._Myentry;
			_No_push = _Right._No_push;
			}
		return (*this);
		}

	int level() const
		{	// get recursion depth
		return (static_cast<int>(_Mylist.size()) - 1);
		}

	void pop()
		{	// pop a level
		_Pop();
		}

	void no_push()
		{	// disable directory recursion
		_No_push = true;
		}

	 const value_type& operator*() const
		{	// return designated value
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Mylist.front().first == _Myiter())
			_DEBUG_ERROR(
				"basic_recursive_directory_iterator is not dereferencable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(_Mylist.front().first != _Myiter());
 #endif /* _ITERATOR_DEBUG_LEVEL */

		return (_Myentry);
		}

	pointer operator->() const
		{	// return pointer to class object
		return (_STD pointer_traits<pointer>::pointer_to(**this));
		}

	_Myt& operator++()
		{	// preincrement
 #if _ITERATOR_DEBUG_LEVEL == 2
		if (_Mylist.front().first == _Myiter())
			_DEBUG_ERROR(
				"basic_recursive_directory_iterator is not incrementable");

 #elif _ITERATOR_DEBUG_LEVEL == 1
		_SCL_SECURE_VALIDATE(_Mylist.front().first != _Myiter());
 #endif /* _ITERATOR_DEBUG_LEVEL */

		if (_No_push || !is_directory(_Mylist.front().first->status()))
			++_Mylist.front().first;
		else
			{	// push down a subdirectory
			path_type _Newpath = _Mylist.front().second
				/ _Mylist.front().first->path();
			++_Mylist.front().first;
			_Mylist.push_front(_Mypair(_Myiter(_Newpath), _Newpath));
			}
		while (1 < _Mylist.size() && _Mylist.front().first == _Myiter())
			_Pop();
		_Get();
		return (*this);
		}

	_Myt operator++(int)
		{	// postincrement
		_Myt _Tmp = *this;
		++*this;
		return (_Tmp);
		}

	bool _Pop()
		{	// pop a directory level
		if (1 < _Mylist.size())
			{	// something to pop, do it
			_Mylist.pop_front();
			return (true);
			}
		else
			return (false);
		}

	bool _Equal(const _Myt& _Right) const
		{	// test for equality
		return (_Mylist.front().first == _Right._Mylist.front().first);
		}

	void _Get()
		{	// prime _Myentry for future gets
		if (_Mylist.front().first != _Myiter())
			{	// item present, get it
			value_type _Dentry = *_Mylist.front().first;
			_Myentry.assign(_Mylist.front().second / _Dentry.path(),
				_Dentry.status(), _Dentry.symlink_status());
			}
		}

private:
	list<_Mypair> _Mylist;
	value_type _Myentry;
	bool _No_push;
	};

template<class _Path> inline
	bool operator==(
		const basic_recursive_directory_iterator<_Path>& _Left,
		const basic_recursive_directory_iterator<_Path>& _Right)
	{	// test for basic_recursive_directory_iterator equality
	return (_Left._Equal(_Right));
	}

template<class _Path> inline
	bool operator!=(
		const basic_recursive_directory_iterator<_Path>& _Left,
		const basic_recursive_directory_iterator<_Path>& _Right)
	{	// test for basic_recursive_directory_iterator inequality
	return (!(_Left == _Right));
	}

typedef basic_recursive_directory_iterator<path>
	recursive_directory_iterator;
typedef basic_recursive_directory_iterator<wpath>
	wrecursive_directory_iterator;

		// FUNCTIONS status AND symlink_status
template<class _Path> inline
	file_status status(const _Path& _Pval)
	{	// get file status
	int _Errno = 0;
	file_type _Ftype = _Stat(_Pval._Ptr(), _Errno);

	return (file_status(_Ftype));
	}

template<class _Path> inline
	file_status status(const _Path& _Pval, error_code& _Code)
	{	// get file status
	int _Errno = 0;
	file_type _Ftype = _Stat(_Pval._Ptr(), _Errno);

	_Code = error_code(_Errno, _STD system_category());
	return (file_status(_Ftype));
	}

template<class _Path> inline
	file_status symlink_status(const _Path& _Pval)
	{	// get symlink file status
	int _Errno = 0;
	file_type _Ftype = _Lstat(_Pval._Ptr(), _Errno);

	return (file_status(_Ftype));
	}

template<class _Path> inline
	file_status symlink_status(const _Path& _Pval, error_code& _Code)
	{	// get symlink file status
	int _Errno = 0;
	file_type _Ftype = _Lstat(_Pval._Ptr(), _Errno);

	_Code = error_code(_Errno, _STD system_category());
	return (file_status(_Ftype));
	}

		// PREDICATES
inline bool status_known(file_status _Stat)
	{	// test if status known
	return (_Stat.type() != status_unknown);
	}

inline bool exists(file_status _Stat)
	{	// test if file exists
	return (status_known(_Stat) && _Stat.type() != file_not_found);
	}

inline bool is_regular(file_status _Stat)
	{	// test for regular file
	return (_Stat.type() == regular_file);
	}

inline bool is_regular_file(file_status _Stat)
	{	// test for regular file
	return (is_regular(_Stat));
	}

inline bool is_directory(file_status _Stat)
	{	// test for directory
	return (_Stat.type() == directory_file);
	}

inline bool is_symlink(file_status _Stat)
	{	// test for symlink
	return (_Stat.type() == symlink_file);
	}

inline bool is_other(file_status _Stat)
	{	// test for other file types
	return (exists(_Stat)
		&& !is_regular(_Stat) && !is_directory(_Stat) && !is_symlink(_Stat));
	}

template<class _Path> inline
	bool exists(const _Path& _Pval)
	{	// test if path exists
	return (exists(status(_Pval)));
	}

template<class _Path> inline
	bool is_regular(const _Path& _Pval)
	{	// test if path is regular
	return (is_regular(status(_Pval)));
	}

template<class _Path> inline
	bool is_regular_file(const _Path& _Pval)
	{	// test if path is regular
	return (is_regular(_Pval));
	}

template<class _Path> inline
	bool is_directory(const _Path& _Pval)
	{	// test if path is directory
	return (is_directory(status(_Pval)));
	}

template<class _Path> inline
	bool is_symlink(const _Path& _Pval)
	{	// test if path is symlink
	return (is_symlink(status(_Pval)));
	}

template<class _Path> inline
	bool is_other(const _Path& _Pval)
	{	// test if path is other file type
	return (is_other(status(_Pval)));
	}

template<class _Path> inline
	bool is_empty(const _Path& _Pval)
	{	// test if path is empty
	file_status _Stat = status(_Pval);

	if (!exists(_Stat))
		_THROW_NCEE(basic_filesystem_error<_Path>,
			"is_empty(p): invalid argument");
	else if (is_directory(_Stat))
		return (basic_directory_iterator<_Path>(_Pval)
			== basic_directory_iterator<_Path>());
	else
		return (file_size(_Pval) == 0);
	}

template<class _Path1,
	class _Path2> inline
	bool equivalent(const _Path1& _Pval1, const _Path2& _Pval2)
	{	// test if paths designate same file
	int _Ans = _Equivalent(_Pval1._Ptr(), _Pval2._Ptr());

	if (_Ans < 0)
		_THROW_NCEE(basic_filesystem_error<_Path1>,
			"equivalent(p1, p2): invalid arguments");
	return (0 < _Ans);
	}

		// ATTRIBUTES
template<class _Path> inline
	_Path current_path()
	{	// get current working directory
	typename _Path::value_type _Dest[_MAX_FILESYS_NAME];
	return (_Current_get(_Dest));
	}

template<class _Path> inline
	void current_path(const _Path& _Pval)
	{	// set current working directory
	_Current_set(_Pval._Ptr());
	}

template<class _Path>
	class _Wrap_init_dir
	{	// wrap the initial directory
public:
	static _Path _Mypath;	// save path at program startup
	};

template<class _Path>
	_Path _Wrap_init_dir<_Path>::_Mypath = current_path<_Path>();

template<class _Path> inline
	_Path initial_path()
	{	// get initial working directory
	return (_Wrap_init_dir<_Path>::_Mypath);
	}

template<class _Path> inline
	_ULonglong file_size(const _Path& _Pval)
	{	// get file size
	return (_File_size(_Pval._Ptr()));
	}

template<class _Path> inline
	space_info space(const _Path& _Pval)
	{	// get space information for volume
	return (_Statvfs(_Pval._Ptr()));
	}

template<class _Path> inline
	time_t last_write_time(const _Path& _Pval)
	{	// get last write time
	return (_Last_write_time(_Pval._Ptr()));
	}

template<class _Path> inline
	void last_write_time(const _Path& _Pval, time_t _Newtime)
	{	// set last write time
	_Last_write_time(_Pval._Ptr(), _Newtime);
	}

		// OPERATIONS
template<class _Path> inline
	bool create_directory(const _Path& _Pval)
	{	// create a directory
	int _Ans = _Make_dir(_Pval._Ptr());

	if (_Ans < 0)
		_THROW_NCEE(basic_filesystem_error<_Path>,
			"create_directory(p): invalid argument");
	else
		return (0 < _Ans);
	}

template<class _Path> inline
	bool remove_directory(const _Path& _Pval)
	{	// remove a directory
	return (_Remove_dir(_Pval._Ptr()));
	}

template<class _Path1,
	class _Path2> inline
	void create_hard_link(const _Path1& _Oldpval,
		const _Path2& _Newpval)
	{	// link _Newpval to _Oldpval
	if (_Link(_Oldpval._Ptr(), _Newpval._Ptr()) != 0)
		_THROW_NCEE(basic_filesystem_error<_Path1>,
			"create_hard_link(p1, p2): invalid arguments");
	}

template<class _Path1,
	class _Path2> inline
	error_code create_hard_link(const _Path1& _Oldpval,
		const _Path2& _Newpval,
		error_code& _Code)
	{	// link _Newpval to _Oldpval
	int _Ans = _Link(_Oldpval._Ptr(), _Newpval._Ptr());
	_Code = error_code(_Ans, _STD system_category());
	return (_Code);
	}

template<class _Path1,
	class _Path2> inline
	void create_symlink(const _Path1& _Oldpval,
		const _Path2& _Newpval)
	{	// symlink _Newpval to _Oldpval
	if (_Symlink(_Oldpval._Ptr(), _Newpval._Ptr()) != 0)
		_THROW_NCEE(basic_filesystem_error<_Path1>,
			"create_symlink(p1, p2): invalid arguments");
	}

template<class _Path1,
	class _Path2> inline
	error_code create_symlink(const _Path1& _Oldpval,
		const _Path2& _Newpval,
		error_code& _Code)
	{	// symlink _Newpval to _Oldpval
	int _Ans = _Symlink(_Oldpval._Ptr(), _Newpval._Ptr());
	_Code = error_code(_Ans, _STD system_category());
	return (_Code);
	}

template<class _Path> inline
	bool remove(const _Path& _Pval)
	{	// remove _Pval
	return (_Unlink(_Pval._Ptr()) == 0);
	}

template<class _Path> inline
	bool remove_filename(const _Path& _Pval)
	{	// remove _Pval
	return (remove(_Pval));
	}

template<class _Path> inline
	bool _Remove_all(const _Path& _Pval, unsigned long &_Ans)
	{	// recursively remove a file or directory, count removed files
	if (is_directory(_Pval))
		{	// empty and remove a directory
		typedef basic_directory_iterator<_Path, false_type> _Myit;
		_Myit _Last;

		for (; ; )
			{	// remove a directory entry
			_Myit _First(_Pval);
			if (_First == _Last)
				break;
			if (!_Remove_all(_Pval / _First->path(), _Ans))
				return (false);
			}
		return (remove_directory(_Pval));
		}
	else if (!remove(_Pval))
		return (false);
	else
		{	// file remove succeeded, count it
		++_Ans;
		return (true);
		}
	}

template<class _Path> inline
	unsigned long remove_all(const _Path& _Pval)
	{	// recursively remove a directory
	unsigned long _Ans = 0;

	_Remove_all(_Pval, _Ans);
	return (_Ans);
	}

template<class _Path1,
	class _Path2> inline
	bool rename(const _Path1& _Oldpval,
		const _Path2& _Newpval)
	{	// rename _Oldpval as _Newpval
	if (exists(_Newpval) && !remove(_Newpval))
		return (false);
	else
		return (_Rename(_Oldpval._Ptr(), _Newpval._Ptr()) == 0);
	}

		// ENUM copy_option

enum class copy_option {	// names for copy options
	fail_if_exists,
	overwrite_if_exists
	};

typedef copy_option _Copy_option;

template<class _Path1,
	class _Path2> inline
	void copy_file(const _Path1& _Oldpval,
		const _Path2& _Newpval,
		_Copy_option _Opt = copy_option::fail_if_exists)
	{	// copy _Oldpval to _Newpval, with attributes
	if (_Copy_file(_Oldpval._Ptr(), _Newpval._Ptr(),
		(int)_Opt == (int)copy_option::fail_if_exists))
		_THROW_NCEE(basic_filesystem_error<_Path1>,
			"copy(p1, p2): invalid arguments");
	}

template<class _Path> inline
	_Path complete(const _Path& _Pval,
		const _Path& _Pbase = initial_path<_Path>())
	{	// complete _Pval with _Pbase
	if (!(_Pbase.is_complete()
		&& (_Pval.is_complete() || !_Pval.has_root_name())))
		_THROW_NCEE(basic_filesystem_error<_Path>,
			"complete(p1, p2): invalid arguments");
	if (_Pval.has_root_name())
		return (_Pval);
	else if (_Pval.has_root_directory())
		return (_Path(_Pbase.root_name()) / _Pval);
	else
		return (_Pbase / _Pval);
	}

template<class _Path> inline
	_Path system_complete(const _Path& _Pval)
	{	// complete _Pval
	return (_Pval.is_complete() ? _Pval : complete(_Pval,
		current_path<_Path>()));
	}

template<class _Path> inline
	bool create_directories(const _Path& _Pval)
	{	// create directory chain
	if (_Pval.empty())
		return (false);
	else if (!exists(_Pval))
		{	// recursively create parent directories, then current
		create_directories(_Pval.branch_path());
		create_directory(_Pval);
		return (true);
		}
	else if (is_directory(_Pval))
		return (false);	// directory already there
	else
		_THROW_NCEE(basic_filesystem_error<_Path>,
			"create_directories(p): bad argument");
	}

template<class _Path> inline
	typename _Path::string_type extension(const _Path& _Pval)
	{	// pick off .extension in leaf, including dot
	return (_Pval.extension());
	}

template<class _Path> inline
	typename _Path::string_type basename(const _Path& _Pval)
	{	// pick off base name in leaf before dot
	return (_Pval.stem());
	}

template<class _Path> inline
	typename _Path::string_type stem(const _Path& _Pval)
	{	// pick off base name in leaf before dot
	return (basename(_Pval));
	}

template<class _Path> inline
	_Path replace_extension(const _Path& _Pval,
		const typename _Path::string_type& _Newext)
	{	// replace extension with _Newext
	_Path _Ans = _Pval;
	return (_Ans.replace_extension(_Newext));
	}
	}	//namespace sys
}	// namespace tr2
_STD_END
 #pragma pop_macro("new")
 #pragma warning(pop)
 #pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _FILESYSTEM_ */

/*
 * Copyright (c) 1992-2012 by P.J. Plauger.  ALL RIGHTS RESERVED.
 * Consult your license regarding permissions and restrictions.
V6.00:0009 */
